use std::sync::Arc;

use axum::middleware;
use axum::routing::post;
use axum::Extension;
use axum::Router;
use axum_app_common::model::AppState;

use axum_app_web::handler;
use axum_app_web::handler::login_handler::login;
use clap::Parser;
use log::error;
use tower::ServiceBuilder;
use tracing::info;

use axum_app_web::middleware::*;

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
    /// 运行: server:运行服务 , setup:安装
    #[arg(short, long)]
    run: Option<String>,
}

#[tokio::main]
async fn main() {
    dotenvy::dotenv().ok();

    // 日志框架初始
    tracing_subscriber::fmt::init();

    let args = Args::parse();
    let arg_run = args.run;

    match arg_run.as_deref() {
        None => serve().await,
        Some("server") => serve().await,
        Some("setup") => setup().await,
        _ => {
            error!("未知的命令");
        }
    }
}

async fn get_app_state() -> anyhow::Result<AppState> {
    // 数据库连接
    let db_conn = match axum_app_common::database::db_connect_from_env().await {
        Ok(db_conn) => db_conn,
        Err(err) => {
            anyhow::bail!("数据库连接失败! : {}", err);
        }
    };

    // redis 连接
    let redis_conn_pool = axum_app_common::database::redis_conn_pool_from_env().unwrap();

    Ok(AppState {
        db_conn,
        redis_conn_pool,
    })
}

async fn setup() {
    let state = get_app_state().await.unwrap();
    let shared_service_store = Arc::new(handler::api_handler::regist_handlers());

    info!("系统RBAC初始化");
    axum_app_web::rbac_setup(&state, Arc::clone(&shared_service_store)).await;
}

async fn serve() {
    let add_str = std::env::var("SERVE_ADDR").unwrap_or("0.0.0.0:3000".to_string());

    let state = get_app_state().await.unwrap();

    let shared_state = Arc::new(state.clone());

    // 中间件组合栈
    let middlewares_stack = ServiceBuilder::new()
        .layer(Extension(shared_state))
        .layer(middleware::from_fn(mid_handler_authc))
        .layer(middleware::from_fn(mid_handler_b));

    // 将 HashMap<&str,BizFn>  -> HashMap<String,BizFn> , 解决生命周期问题
    let fn_map = handler::api_handler::regist_handlers();
    // 打印注册的信息
    for (k, v) in fn_map.get_service_store_info() {
        info!("注册服务: {k}({v})");
    }

    let shared_service_store = Arc::new(fn_map);

    let app = Router::new()
        .nest(
            "/api",
            handler::api_handler::router(Arc::clone(&shared_service_store)),
        )
        .layer(middlewares_stack)
        .route("/login", post(login))
        .with_state(state);

    let listener = tokio::net::TcpListener::bind(&add_str).await.unwrap();
    info!("server on {}", add_str);
    axum::serve(listener, app).await.unwrap();
}
